package com.adee.gulimall.product.service.impl;

import com.adee.gulimall.common.constant.ProductConstant;
import com.adee.gulimall.common.to.SkuReductionTo;
import com.adee.gulimall.common.to.SpuBoundTo;
import com.adee.gulimall.common.to.es.SkuESModel;
import com.adee.gulimall.common.utils.PageUtils;
import com.adee.gulimall.common.utils.Query;
import com.adee.gulimall.util.utils.R;
import com.adee.gulimall.product.dao.SpuInfoDao;
import com.adee.gulimall.product.entity.*;
import com.adee.gulimall.product.feign.CouponFeignService;
import com.adee.gulimall.product.feign.ElasticSearchFeignService;
import com.adee.gulimall.product.feign.WareFeignService;
import com.adee.gulimall.product.service.*;
import com.adee.gulimall.product.vo.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {
    @Autowired
    SpuInfoDao spuInfoDao;

    @Autowired
    SpuInfoDescService spuInfoDescService;

    @Autowired
    SpuImagesService spuImagesService;

    @Autowired
    AttrService attrService;

    @Autowired
    ProductAttrValueService productAttrValueService;

    @Autowired
    SkuInfoService skuInfoService;

    @Autowired
    SkuImagesService skuImagesService;

    @Autowired
    SkuSaleAttrValueService skuSaleAttrValueService;

    @Autowired
    CouponFeignService couponFeignService;

    @Autowired
    BrandService brandService;

    @Autowired
    CategoryService categoryService;

    @Autowired
    WareFeignService wareFeignService;

    @Autowired
    ElasticSearchFeignService elasticSearchFeignService;


    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        QueryWrapper<SpuInfoEntity> wrapper = new QueryWrapper<>();

        String key = (String) params.get("key");
        if(!StringUtils.isEmpty(key)) {
            wrapper.and(w -> {
                w.eq("id", key).or().like("spu_name", key);
            });
        }
        String status = (String) params.get("status");
        if(!StringUtils.isEmpty(status)) {
            wrapper.and(w -> {
                w.eq("publish_status", status);
            });
        }
        String brandId = (String) params.get("brandId");
        if(!StringUtils.isEmpty(brandId) && !"0".equals(brandId)) {
            wrapper.and(w -> {
                w.eq("brand_id", brandId);
            });
        }
        String catelogId = (String) params.get("catelogId");
        if(!StringUtils.isEmpty(catelogId) && !"0".equals(catelogId)) {
            wrapper.and(w -> {
                w.eq("catalog_id", catelogId);
            });
        }
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                wrapper
        );
        return new PageUtils(page);
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {

        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );

        return new PageUtils(page);
    }

    @Transactional
    @Override
    public void saveSpuInfo(SpuSaveVo vo) {
        // pms_spu_info为spu基本信息表，pms_spu_info_desc为spu基本信息描述图片表，pms_spu_images为图片集表
        // 1.保存spu商品基本信息，pms_spu_info
        SpuInfoEntity info = new SpuInfoEntity();
        BeanUtils.copyProperties(vo, info);
        info.setCreateTime(new Date());
        info.setUpdateTime(new Date());
        this.saveBaseSpuInfo(info);

        // 2.保存spu的基本信息描述，pms_spu_info_desc
        SpuInfoDescEntity desc = new SpuInfoDescEntity();
        desc.setSpuId(info.getId());
        List<String> descList = vo.getDecript();
        desc.setDecript(String.join(",", descList));
        this.saveSpuInfoDesc(desc);

        // 3.保存spu的图片集，pms_spu_images
        List<String> images = vo.getImages();
        spuImagesService.saveImages(info.getId(), images);

        // 4.保存spu的规格参数，pms_product_attr_value为纵表，存储spu的规格参数名和规格参数值
        List<BaseAttrs> baseAttrs = vo.getBaseAttrs();
        List<ProductAttrValueEntity> avList = baseAttrs.stream().map(attr -> {
            ProductAttrValueEntity av = new ProductAttrValueEntity();
            av.setAttrId(attr.getAttrId());
            av.setAttrName(attrService.getNameById(attr.getAttrId()));
            av.setAttrValue(attr.getAttrValues());
            av.setQuickShow(attr.getShowDesc());
            av.setSpuId(info.getId());
            return av;
        }).collect(Collectors.toList());
        productAttrValueService.saveBatch(avList);
        // 5.保存当前spu对应的所有sku信息
        // 5.1.sku基本信息（sku的名字、标题、副标题等等），pms_sku_info
        List<Skus> skus = vo.getSkus();
        skus.forEach(item -> {
            SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
            BeanUtils.copyProperties(item, skuInfoEntity);
            skuInfoEntity.setBrandId(info.getBrandId());
            skuInfoEntity.setCatalogId(info.getCatalogId());
            skuInfoEntity.setSaleCount(0L);
            skuInfoEntity.setSpuId(info.getId());
            // 找默认图片
            String defaultImg = null;
            for (Images img : item.getImages()) {
                if(img.getDefaultImg() == 1)
                    defaultImg = img.getImgUrl();
            }
            skuInfoEntity.setSkuDefaultImg(defaultImg);
            skuInfoService.save(skuInfoEntity);
            Long skuId = skuInfoEntity.getSkuId();
            // 5.2.sku的图片信息，pms_sku_images
            List<SkuImagesEntity> skuImageList = item.getImages().stream().map(img -> {
                SkuImagesEntity e = new SkuImagesEntity();
                e.setSkuId(skuId);
                e.setImgUrl(img.getImgUrl());
                e.setDefaultImg(img.getDefaultImg());
                return e;
            }).filter(img -> !StringUtils.isEmpty(img.getImgUrl()))
                    .collect(Collectors.toList());
            skuImagesService.saveBatch(skuImageList);
            // 5.3.sku的销售属性信息，pms_sku_sale_attr_value
            List<Attr> saleAttrs = item.getAttr();
            List<SkuSaleAttrValueEntity> saleAttrList = saleAttrs.stream().map(a -> {
                SkuSaleAttrValueEntity e = new SkuSaleAttrValueEntity();
                BeanUtils.copyProperties(a, e);
                e.setSkuId(skuId);
                return e;
            }).collect(Collectors.toList());
            skuSaleAttrValueService.saveBatch(saleAttrList);
            // 5.4.spu积分信息
            Bounds bounds = vo.getBounds();
            SpuBoundTo to = new SpuBoundTo();
            BeanUtils.copyProperties(bounds, to);
            to.setSpuId(info.getId());
            R r = couponFeignService.saveSpuBounds(to);
            if(r.getCode() != 0) {
                log.error("远程保存spu积分信息失败：" + info.toString());
            }
            // 5.5.sku的优惠信息和满减信息，跨库操作gulimall_sms，调用其他微服务
            // sms_sku_ladder打折表，sms_sku_full_reduction满减表，sms_member_price会员价格表，sms_spu_bounds:spu积分表
            SkuReductionTo reductionTo = new SkuReductionTo();
            BeanUtils.copyProperties(item, reductionTo);
            reductionTo.setSkuId(skuId);
            // 满几件，满多少钱都需要大于0
            if(reductionTo.getFullCount() > 0 || reductionTo.getFullPrice().compareTo(new BigDecimal("0")) == 1) {
                R r1 = couponFeignService.saveSkuReduction(reductionTo);
                if(r1.getCode() != 0) {
                    log.error("远程保存sku满减优惠信息失败：" + info.toString());
                }
            }

        });

    }

    @Override
    public void saveBaseSpuInfo(SpuInfoEntity spuInfoEntity) {
        spuInfoDao.insert(spuInfoEntity);
    }

    @Override
    public void saveSpuInfoDesc(SpuInfoDescEntity desc) {
        spuInfoDescService.save(desc);
    }


    // 商品上架
    @Transactional
    @Override
    public void spuUp(Long spuId) {
        // 查询spuId下的全部可被检索的基本属性
        List<ProductAttrValueEntity> spuAttrValues = productAttrValueService.list(
                new QueryWrapper<ProductAttrValueEntity>()
                        .eq("spu_id", spuId));
        List<SkuESModel.Attrs> attrs = spuAttrValues.stream().filter(attr -> {
            AttrEntity a = attrService.getById(attr.getAttrId());
            return a != null && a.getSearchType() == ProductConstant.AttrSearchTypeEnum.ATTR_TYPE_BASE.getCode();
        }).map(attr -> {
            SkuESModel.Attrs a = new SkuESModel.Attrs();
            BeanUtils.copyProperties(attr, a);
            return a;
        }).collect(Collectors.toList());
        // 1.查出spuId下的所有sku信息
        List<SkuInfoEntity> skuList = this.getSkuListBySupId(spuId);
        List<SkuESModel> skuESModels = skuList.stream().map(sku -> {
            SkuESModel model = new SkuESModel();
            BeanUtils.copyProperties(sku, model);
            model.setSkuPrice(sku.getPrice());
            model.setSkuImg(sku.getSkuDefaultImg());
            // 发送远程调用查询是否有库存，gulimall-ware
            try {
                R<Integer> r = wareFeignService.skuStock(sku.getSkuId());
                if (r != null && r.getCode() == 0) {
                    if (r.getData() > 0) {
                        model.setHasStock(true);
                    } else {
                        model.setHasStock(false);
                    }
                }
            } catch (Exception e) {
                log.error("查询库存异常，设置默认库存是否存在：true", e);
                model.setHasStock(true);
            }

            // 热度评分，暂设为0
            model.setHotScore(0L);
            BrandEntity brand = brandService.getById(sku.getBrandId());
            model.setBrandName(brand.getName());
            model.setBrandImg(brand.getLogo());
            model.setCatalogName(categoryService.getById(sku.getCatalogId()).getName());
            // 查询sku所有可被检索的基本属性，sku基本属性都是来自spu的，所以根据spuId只查询一次即可
            model.setAttrs(attrs);
            // 发送给es进行保存，gulimall-search
            return model;
        }).collect(Collectors.toList());
        R r = elasticSearchFeignService.productStatusUp(skuESModels);
        if(r.getCode() == 0) {
            log.info("商品上架成功");
            this.updateSpuStatus(spuId, ProductConstant.StatusEnum.SPU_UP.getCode());
        } else {
            log.error("商品上架失败：{}", r.getData());
            //TODO 重复调用问题，接口幂等性？重试机制？

        }
    }

    @Override
    public List<SkuInfoEntity> getSkuListBySupId(Long spuId) {
        List<SkuInfoEntity> skuInfoEntities = skuInfoService.getBaseMapper().selectList(
                new QueryWrapper<SkuInfoEntity>()
                        .eq("spu_id", spuId));
        return skuInfoEntities;
    }

    @Override
    public void updateSpuStatus(Long spuId, int code) {
        SpuInfoEntity spu = new SpuInfoEntity();
        spu.setId(spuId);
        spu.setPublishStatus(ProductConstant.StatusEnum.SPU_UP.getCode());
        spu.setUpdateTime(new Date());
        this.updateById(spu);
    }
}